ASP.NET Core MVC 跟 ASP.NET MVC 一樣也提供了 Filter
的功能,以 AOP 的觀念在執行 Action 的前後處理資料。第一次看到 Middleware 的時候有想說阿這不是跟 Filter
一樣嗎,但其實兩者的執行順序是有差別的。Middleware
是 ASP.NET Core 應用程式對 HTTP 請求跟回應的處理,如果應用程式剛好有加入 MVC 的中介層,在 ASP.NET Core MVC 的 Action 執行前後就會有不同的 Filter
來處理請求跟回應。說這麼多不如直接看張圖,藍色虛線框框內的才是 MVC 的 Filter
pipeline,框框上方的則是 Middleware
pipeline:
圖片來源:https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters
ASP.NET Core MVC 框架中的 Filter
有幾種類型 (Stage),會依照順序來執行,不像 Middleware 可以這麼自由發揮。
401
之類的)。所有 Filter
的執行流程大概是這樣:
圖片來源依然是:https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters
不同類型的 Filter
需要實作個別的介面,實作各自的 On{Stage}
方法,都有分為同步與非同步的方式:
public class AuthorizationFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
// 如果驗證失敗,可以讓 pipeline 短路
// context.Result = new UnauthorizedResult();
context.HttpContext.Response.WriteAsync("Executing AuthorizationFilter. \r\n");
}
}
public class AsyncAuthorazationFilter : IAsyncAuthorizationFilter
{
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
await context.HttpContext.Response.WriteAsync("Executing AsyncAuthorizationFilter. \r\n");
}
}
public class ResourceFilter : IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
context.HttpContext.Response.WriteAsync("Executing ResourceFilter. \r\n");
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
context.HttpContext.Response.WriteAsync("ResourceFilter is executed. \r\n");
}
}
public class AsyncResouceFilter : IAsyncResourceFilter
{
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
{
await context.HttpContext.Response.WriteAsync("Executing AsyncResouceFilter. \r\n");
await next();
await context.HttpContext.Response.WriteAsync("AsyncResouceFilter is executed. \r\n");
}
}
public class ActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
context.HttpContext.Response.WriteAsync("Executing AsyncActionFilter. \r\n");
}
public void OnActionExecuted(ActionExecutedContext context)
{
context.HttpContext.Response.WriteAsync("ActionFilter is executed. \r\n");
}
}
public class AsyncActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
await context.HttpContext.Response.WriteAsync("AsyncActionFilter AsyncActionFilter. \r\n");
await next();
await context.HttpContext.Response.WriteAsync("AsyncActionFilter is executed. \r\n");
}
}
public class ExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
context.HttpContext.Response.WriteAsync("Executing ExceptionFilter. \r\n");
}
}
public class AsyncExceptionFilter : IAsyncExceptionFilter
{
public async Task OnExceptionAsync(ExceptionContext context)
{
await context.HttpContext.Response.WriteAsync("AsyncExceptionFilter ExceptionFilter. \r\n");
}
}
public class ResultFilter : IResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.WriteAsync("Executing ResultFilter. \r\n");
}
public void OnResultExecuted(ResultExecutedContext context)
{
context.HttpContext.Response.WriteAsync("ResultFilter is executed. \r\n");
}
}
public class AsyncResultFilter : IAsyncResultFilter
{
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
await context.HttpContext.Response.WriteAsync("AsyncActionFilter AsyncResultFilter. \r\n");
await next();
await context.HttpContext.Response.WriteAsync("AsyncResultFilter is executed. \r\n");
}
}
一個自訂的 Filter
類別也可以同時實作多種不同 {Stage}Filter
。
要把 Filter
加進 MVC 執行過程中有兩種方式:
Startup.ConfigureServices
加入 MVC 服務時註冊,這邊註冊的 Filter
會影響到所有的請求跟回應:public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Filters.Add(new ResourceFilter());
options.Filters.Add<ExceptionFilter>();
options.Filters.Add<ResultFilter>();
});
}
Filter
的 Controller 或 Action 註冊。可以用 [TypeFilter(Type)]
註冊,或者讓原本的 ActionFilter
額外繼承 Attribute
:[TypeFilter(typeof(AuthorizationFilter))]
public class FiltersController : Controller
{
[ActionFilter]
public IActionResult Index()
{
return Content("ASP.NET Core MVC Filters Example");
}
}
public class ActionFilter : ActionFilterAttribute
// or this
// public class ActionFilter : Attribute, IActionFilter
{
public override void OnActionExecuting(ActionExecutingContext context)
{
context.HttpContext.Response.WriteAsync("Executing AsyncActionFilter. \r\n");
}
public override void OnActionExecuted(ActionExecutedContext context)
{
context.HttpContext.Response.WriteAsync("ActionFilter is executed. \r\n");
}
}
執行結果:
Filter
執行順序除了依上面看到五種 Stage 以先進後出的順序執行外,還會依 Global > Controller > Action 的註冊順序來執行。